2 * Copyright (C) 2023 by Claudio Cambra <claudio.cambra@nextcloud.com>
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
11 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
19 class ClientCommunicationService: NSObject, NSFileProviderServiceSource, NSXPCListenerDelegate, ClientCommunicationProtocol {
20 let listener = NSXPCListener.anonymous()
21 let serviceName = NSFileProviderServiceName("com.nextcloud.desktopclient.ClientCommunicationService")
22 let fpExtension: FileProviderExtension
24 init(fpExtension: FileProviderExtension) {
25 Logger.desktopClientConnection.debug("Instantiating client communication service")
26 self.fpExtension = fpExtension
30 func makeListenerEndpoint() throws -> NSXPCListenerEndpoint {
31 listener.delegate = self
33 return listener.endpoint
36 func listener(_ listener: NSXPCListener, shouldAcceptNewConnection newConnection: NSXPCConnection) -> Bool {
37 newConnection.exportedInterface = NSXPCInterface(with: ClientCommunicationProtocol.self)
38 newConnection.exportedObject = self
39 newConnection.resume()
43 //MARK: - Client Communication Protocol methods
45 func getExtensionAccountId(completionHandler: @escaping (String?, Error?) -> Void) {
46 let accountUserId = self.fpExtension.domain.identifier.rawValue
47 Logger.desktopClientConnection.info("Sending extension account ID \(accountUserId, privacy: .public)")
48 completionHandler(accountUserId, nil)
51 func configureAccount(withUser user: String,
55 Logger.desktopClientConnection.info("Received configure account information over client communication service")
56 self.fpExtension.setupDomainAccount(user: user,
62 func removeAccountConfig() {
63 self.fpExtension.removeAccountConfig()
66 func createDebugLogString(completionHandler: ((String?, Error?) -> Void)!) {
67 if #available(macOSApplicationExtension 12.0, *) {
68 let (logs, error) = Logger.logEntries()
69 guard error == nil else {
70 Logger.logger.error("Cannot create debug archive, received error: \(error, privacy: .public)")
71 completionHandler(nil, error)
74 guard let logs = logs else {
75 Logger.logger.error("Canot create debug archive with nil logs.")
76 completionHandler(nil, nil)
79 completionHandler(logs.joined(separator: "\n"), nil)
83 func getFastEnumerationState(completionHandler: @escaping (Bool, Bool) -> Void) {
84 let enabled = fpExtension.config.fastEnumerationEnabled
85 let set = fpExtension.config.fastEnumerationSet
86 completionHandler(enabled, set)
89 func setFastEnumerationEnabled(_ enabled: Bool) {
90 fpExtension.config.fastEnumerationEnabled = enabled
91 Logger.fileProviderExtension.info("Fast enumeration setting changed to: \(enabled, privacy: .public)")
93 guard enabled else { return }
94 // If enabled, start full enumeration
95 guard let fpManager = NSFileProviderManager(for: fpExtension.domain) else {
96 let domainName = self.fpExtension.domain.displayName
97 Logger.fileProviderExtension.error("Could not get file provider manager for domain \(domainName, privacy: .public), cannot run enumeration after fast enumeration setting change")
101 fpManager.signalEnumerator(for: .workingSet) { error in
103 Logger.fileProviderExtension.error("Error signalling enumerator for working set, received error: \(error!.localizedDescription, privacy: .public)")